/**
 * 二进制像素点
 */
export class V3ProBinaryPixel {
  constructor(
    public width: number,
    public height: number,
    public offsetWidth: number = 0,
    public offsetHeight: number = 0,
  ) {
    this.__count = width * height;
    this.__data = new Uint32Array(Math.ceil(this.__count / 32));
  }

  private readonly __count: number;
  private readonly __data;
  private __trueCount = 0;

  private __cur(x: number, y: number) {
    const cur = (y - this.offsetHeight) * this.width + (x - this.offsetWidth);
    if (cur >= this.__count) throw new Error("超出范围");
    return cur;
  }

  isTrue(x: number, y: number): boolean {
    const cur = this.__cur(x, y);
    return ((this.__data[cur >> 5] >> cur % 32) & 1) === 1;
  }

  isFalse(x: number, y: number) {
    return !this.isTrue(x, y);
  }

  setTrue(x: number, y: number) {
    if (this.isFalse(x, y)) this.__trueCount++;
    else return;
    const cur = this.__cur(x, y);
    this.__data[cur >> 5] |= 1 << cur % 32;
  }

  setFalse(x: number, y: number) {
    if (this.isTrue(x, y)) this.__trueCount--;
    else return;
    const cur = this.__cur(x, y);
    this.__data[cur >> 5] &= ~(1 << cur % 32);
  }

  trueCount() {
    return this.__trueCount;
  }

  size() {
    return this.__count;
  }

  forEach(callback: (value: boolean, x: number, y: number) => void) {
    let cur = 0;
    for (let i = 0; i < this.__data.length; i++) {
      for (let j = 0; j < 32 && cur < this.__count; j++, cur++) {
        callback(
          ((this.__data[i] >> j) & 1) === 1,
          (cur % this.width) + this.offsetWidth,
          Math.floor(cur / this.width) + this.offsetHeight,
        );
      }
    }
  }

  forEachTrue(callback: (x: number, y: number) => void) {
    this.forEach((value, x, y) => {
      if (value) callback(x, y);
    });
  }
}
